using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using Common.Utilities.Dispatcher;

namespace WindowsUserControl.Dialogs
{
    /// <summary>
    /// 
    /// </summary>
    /// <param name="type"></param>
    public delegate void SelectedType(Type type);

    /// <summary>
    /// 
    /// </summary>
    public partial class ReflectionBrowser : Form
    {
        private Dictionary<string, string > _TypeNameDllFilePathMappings;
        private Dictionary<string, List<string>> _TypeNamesByNamespaceName;

        /// <summary>
        /// 
        /// </summary>
        public event SelectedType OnTypeSelected;
        /// <summary>
        /// 
        /// </summary>
        public ReflectionBrowser()
        {
            InitializeComponent();
        }

        private void ReflectionBrowser_Load(object sender, EventArgs e)
        {
            this._TypeNameDllFilePathMappings = new Dictionary<string, string>();
            this._TypeNamesByNamespaceName =new Dictionary<string, List<string>>();
            string binFolderPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            DirectoryInfo dirInfo=new DirectoryInfo(binFolderPath);
            FileInfo[] dllInfos = dirInfo.GetFiles("*.dll", SearchOption.TopDirectoryOnly);
            foreach(FileInfo dllInfo in dllInfos)
            {
                Assembly assem = Assembly.LoadFile(dllInfo.FullName);
                Type[] types = assem.GetTypes();
                foreach(Type type in types)
                {
                    if (type.IsSubclassOf(typeof(InstructionBase)) || type.IsSubclassOf(typeof(ResultBase)))
                    {
                        string nsName = type.Namespace;
                        if (this._TypeNamesByNamespaceName.ContainsKey(nsName))
                        {
                            List<string> typeNames = this._TypeNamesByNamespaceName[nsName];
                            typeNames.Add(type.FullName);
                            this._TypeNamesByNamespaceName[nsName] = typeNames;
                        }
                        else
                        {
                            List<string> typeNames = new List<string>();
                            typeNames.Add(type.FullName);
                            this._TypeNamesByNamespaceName.Add(nsName, typeNames);
                        }
                        if (!this._TypeNameDllFilePathMappings.ContainsKey(type.FullName))
                        {
                            this._TypeNameDllFilePathMappings.Add(type.FullName, dllInfo.FullName);
                        }
                    }
                }
            }

            this.PopulateNamespaces();
        }

        private void PopulateNamespaces()
        {
            this.cbo_Namespaces.Items.Clear();
            this.cbo_Namespaces.SelectedIndex = -1;
            this.cbo_Namespaces.Text = string.Empty;

            if(this._TypeNamesByNamespaceName !=null && this._TypeNamesByNamespaceName.Count>0)
            {
                List<string> nsNameList = new List<string>();
                foreach(string nsKey in this._TypeNamesByNamespaceName.Keys)
                {
                    nsNameList.Add(nsKey);
                }
                nsNameList.Sort();
                foreach(string nsName in nsNameList)
                {
                    this.cbo_Namespaces.Items.Add(nsName);
                }
            }
        }

        private void cbo_Namespaces_SelectedIndexChanged(object sender, EventArgs e)
        {
            if(this.cbo_Namespaces.SelectedIndex>=0)
            {
                string nsName = this.cbo_Namespaces.SelectedItem.ToString();
                List<string> typeNames = this._TypeNamesByNamespaceName[nsName];
                this.cbo_Objects.Items.Clear();
                this.cbo_Objects.SelectedIndex = -1;
                this.cbo_Objects.Text = string.Empty;
                foreach(string typeName in typeNames)
                {
                    this.cbo_Objects.Items.Add(typeName);
                }
            }
        }

        private void cbo_Objects_SelectedIndexChanged(object sender, EventArgs e)
        {
            if(this.cbo_Objects.SelectedIndex>=0)
            {
                string typeFullName = this.cbo_Objects.SelectedItem.ToString();
                string dllPath = this._TypeNameDllFilePathMappings[typeFullName];
                Assembly assem = Assembly.LoadFile(dllPath);
                Type type = assem.GetType(typeFullName);
                FieldInfo[] fields = type.GetFields();
                
                StringBuilder buffer=new StringBuilder();
                foreach(FieldInfo field in fields)
                {
                    buffer.Append(field.Name + Environment.NewLine);
                }

                PropertyInfo[] props = type.GetProperties();
                foreach(PropertyInfo prop in props)
                {
                    buffer.Append(prop.Name + Environment.NewLine);
                }
                this.rt_Fields.Text = buffer.ToString().Trim();
            }
        }

        private void btn_OK_Click(object sender, EventArgs e)
        {
            if (this.cbo_Objects.SelectedIndex >= 0)
            {
                string typeFullName = this.cbo_Objects.SelectedItem.ToString();
                string dllPath = this._TypeNameDllFilePathMappings[typeFullName];
                Assembly assem = Assembly.LoadFile(dllPath);
                Type type = assem.GetType(typeFullName);
                if (this.OnTypeSelected != null)
                {
                    this.OnTypeSelected(type);
                }

                this.Close();
            }
        }

        private void btn_Cancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }
    }
}